/*
 *  Copyright 2008 Mark Ashworth <javameme@gmail.com>.
 * 
 *  Licensed under the GNU General Public License v3 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.gnu.org/licenses/gpl-3.0.html
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package xperiment.metaphor.model.xml;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import metaphor.persistence.xml.PersistentClassResolver;
import metaphor.persistence.xml.ReferenceResolver;

/**
 *
 * @author Mark Ashworth <javameme@gmail.com>
 * @version 1.0.0
 */
public class ReferenceResolvers implements ReferenceResolver {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    /*
     * Resolver to resolve XML elements to persistent classes 
     */
    private PersistentClassResolver classResolver;
    /*
     * The list of reference reslvers 
     */
    private List<ReferenceResolver> resolvers = new ArrayList<ReferenceResolver>();

    /**
     * The list of reference reslvers 
     * @return List<ReferenceResolver>
     */
    public List<ReferenceResolver> getResolvers() {
        if (this.resolvers == null) {
            this.resolvers = new ArrayList<ReferenceResolver>();
        }
        return resolvers;
    }

    /**
     * The list of reference reslvers 
     * @param resolvers The new value
     */
    public void setResolvers(List<ReferenceResolver> resolvers) {
        this.resolvers = resolvers;
    }

    public void addResolver(ReferenceResolver resolver) {
        if (this.resolvers == null) {
            this.resolvers = new ArrayList<ReferenceResolver>();
        }
        this.resolvers.add(resolver);
    }
    /**
     * The persistent class resolver to resolve XML elements to persistent classes
     * @return PersistentClassResolver
     */
    public PersistentClassResolver getClassResolver() {
        if (classResolver == null) {
            this.classResolver = new DefaultPersistentClassResolver();
        }
        return classResolver;
    }

    /**
     * The persistent class resolver to resolve XML elements to persistent classes
     * @param classResolver The new value
     */
    public void setClassResolver(PersistentClassResolver classResolver) {
        this.classResolver = classResolver;
    }
    
    /**
     * Resolves the XML element to a persisted instance
     * @param persistentClass The persisted class that the element represents
     * @param element The XML element
     * @return The serializable id of the persisted instance or null
     */
    @Override
    public void resolve(Element element) {
        
        List<Element> references = element.elements();
        for (Element reference : references) {
            Class persistentClass = getClassResolver().resolve(reference);
            if (persistentClass != null) {
                
                Serializable id = null;
                for (ReferenceResolver resolver : resolvers) {
                    if (resolver.supports(reference)) {
                        
                        if (resolver.getClassResolver() == null) {
                            resolver.setClassResolver(getClassResolver());
                        }
                        
                        try {
                            resolver.resolve(reference);
                        } catch (Throwable e) {
                            logger.error("Error resolving reference in {}, \r\nError: {}", element.asXML(), e.getMessage());
                        }
                    }
                }
            }
        }
    }
    
    /**
     * Determines if the XML element is supported by this resolver
     * @param element The ement to determine if it is supported by the resolver
     * @return boolean
     */
    @Override
    public boolean supports(Element element) {
        return true;
    }
}
